import path from 'node:path';

import { IpcMain } from 'electron';

import { log } from '../logger';
import { toKebabCase } from '../utils/stringUtils';
import handlerAdapter from './handlerAdapter';
import { discoverApiModules } from './loader';

export class IpcServer {
  private ipcMain: IpcMain;
  private registeredChannels = new Set<string>();

  constructor(ipcMainInstance: IpcMain) {
    this.ipcMain = ipcMainInstance;
    log.info('[IpcServer] Initializing...');
    this._registerIpcHandlers();
  }

  private _registerIpcHandlers(): void {
    log.info('[IpcServer] Starting to register IPC handlers from API modules...');
    const discoveredModules = discoverApiModules();
    let handlersRegisteredCount = 0;

    if (discoveredModules.length === 0) {
      log.warn('[IpcServer] No API modules found by loader.');
      return;
    }

    log.info(`[IpcServer] Processing ${discoveredModules.length} discovered modules...`);

    const prefixToRemove = '../../api/';

    for (const { path: relativePath, module } of discoveredModules) {
      let channelPrefix: string | undefined;

      if (relativePath.startsWith(prefixToRemove)) {
        const corePath = relativePath.substring(prefixToRemove.length);
        const parsed = path.parse(corePath.replace(/\\/g, '/'));
        const dirParts = parsed.dir ? parsed.dir.split('/') : [];
        const filePart = parsed.name;
        channelPrefix = ['api', ...dirParts, filePart]
          .filter((part) => part)
          .map(toKebabCase)
          .join('/');
        log.debug(`[IpcServer] Calculated channel prefix for ${relativePath}: ${channelPrefix}`);
      } else {
        log.warn(
          `[IpcServer] Module path ${relativePath} does not start with expected prefix '${prefixToRemove}'. Skipping.`
        );
        continue;
      }

      let moduleHandled = false;
      let moduleRegisteredCount = 0;

      if (module.handlers && typeof module.handlers === 'object') {
        const handlersObject = module.handlers as Record<string, (...args: any[]) => Promise<any>>;
        log.debug(`[IpcServer] Found 'handlers' object (Pattern A) from ${relativePath}. Processing entries...`);

        for (const key in handlersObject) {
          if (Object.prototype.hasOwnProperty.call(handlersObject, key)) {
            const businessFunc = handlersObject[key];
            if (typeof businessFunc === 'function') {
              const operationName = toKebabCase(key);
              const channel = `/${channelPrefix}/${operationName}`;

              if (this._registerHandler(channel, businessFunc)) {
                handlersRegisteredCount++;
                moduleRegisteredCount++;
              }
            } else {
              log.warn(
                `[IpcServer] Exported handler for key "${key}" in 'handlers' object from ${relativePath} is not a function. Skipping.`
              );
            }
          }
        }
        if (moduleRegisteredCount > 0) {
          log.info(
            `[IpcServer] Registered ${moduleRegisteredCount} handlers from 'handlers' object in ${relativePath}`
          );
        }
        moduleHandled = true;
      }

      if (!moduleHandled) {
        log.debug(`[IpcServer] Checking for individual function exports (Pattern B) from ${relativePath}...`);
        let individualFuncRegisteredCount = 0;
        for (const exportKey in module) {
          if (
            Object.prototype.hasOwnProperty.call(module, exportKey) &&
            exportKey !== 'default' &&
            !exportKey.startsWith('_') &&
            typeof module[exportKey] === 'function'
          ) {
            const businessFunc = module[exportKey] as (...args: any[]) => Promise<any>;
            const operationName = toKebabCase(exportKey);
            const channel = `/${channelPrefix}/${operationName}`;

            if (this._registerHandler(channel, businessFunc)) {
              handlersRegisteredCount++;
              individualFuncRegisteredCount++;
            }
          }
        }
        if (individualFuncRegisteredCount > 0) {
          log.info(
            `[IpcServer] Registered ${individualFuncRegisteredCount} handlers from individual function exports in ${relativePath}`
          );
          moduleHandled = true;
        }
      }

      if (!moduleHandled) {
        log.debug(`[IpcServer] Module at ${relativePath} did not provide any handlers via Pattern A or B.`);
      }
    }

    log.info(`[IpcServer] Finished processing modules. Total IPC handlers registered: ${handlersRegisteredCount}.`);
    log.debug('[IpcServer] Registered IPC channels:', Array.from(this.registeredChannels).sort());
  }

  private _registerHandler(channel: string, businessFunc: (...args: any[]) => Promise<any>): boolean {
    if (this.registeredChannels.has(channel)) {
      log.error(`[IpcServer] Duplicate channel registration detected for "${channel}". Registration skipped.`);
      return false;
    }

    try {
      log.info(`[IpcServer] Registering IPC handler for channel: "${channel}"`);
      this.ipcMain.handle(channel, async (_event, ...args) => {
        log.debug(`[IpcServer] IPC Channel "${channel}" invoked with args:`, args);

        // 使用通用响应处理器
        return await handlerAdapter.execute(businessFunc, args, {
          channelName: channel,
          type: 'ipc'
        });
      });
      this.registeredChannels.add(channel);
      return true;
    } catch (error) {
      log.error(`[IpcServer] Failed to register handler for channel "${channel}":`, error);
      return false;
    }
  }
}
